package com.ccp.dev.workflow.listener;

import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.system.consts.SecretUtil;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.system.service.SysUserService;
import com.ccp.dev.workflow.bpmconst.BpmConst;
import com.ccp.dev.workflow.model.TaskOpinion;
import com.ccp.dev.workflow.model.bpm.TaskExecutor;
import com.ccp.dev.workflow.model.bpm.TaskSignData;
import com.ccp.dev.workflow.service.AgentSettingService;
import com.ccp.dev.workflow.service.BpmProStatusService;
import com.ccp.dev.workflow.service.TaskOpinionService;
import com.ccp.dev.workflow.service.bpm.BpmNodeUserUtil;
import com.ccp.dev.workflow.service.bpm.TaskSignDataService;
import com.ccp.dev.workflow.service.bpm.thread.MessageUtil;
import com.ccp.dev.workflow.service.bpm.thread.TaskThreadService;
import com.ccp.dev.workflow.service.bpm.thread.TaskUserAssignService;
import org.flowable.task.api.Task;
import org.flowable.task.service.delegate.DelegateTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

/**
 * ClassDescribe:
 * 会签任务创建监听器
 * @author :wangcheng
 * Date: 2019-05-13
 */
@Component
public class TaskSignCreateListener extends BaseTaskListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(TaskSignCreateListener.class);

    @Resource
    private TaskOpinionService taskOpinionService;
    @Resource
    private AgentSettingService agentSettingService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private BpmProStatusService bpmProStatusService;
    @Resource
    private TaskUserAssignService taskUserAssignService;
    @Resource
    private TaskSignDataService taskSignDataService;

    @Override
    protected int getScriptType() {
        return BpmConst.START_SCRIPT;
    }

    @Override
    protected void execute(DelegateTask delegateTask, String procDefId, String nodeId) {
        // 设定任务状态为待审批
        delegateTask.setDescription(TaskOpinion.STATUS_CHECKING.toString());

        TaskOpinion taskOpinion = new TaskOpinion(delegateTask);
        taskOpinion.setOpinionId(UUIDUtils.getUUIDFor32());
        taskOpinionService.add(taskOpinion);

        // 获取任务执行人
        TaskExecutor taskExecutor = (TaskExecutor)delegateTask.getVariable("assignee");

        // 分配用户
        assignTaskExecutor(delegateTask, taskExecutor);

        // 把新生成的任务加至执行堆栈
        TaskThreadService.addTask((Task) delegateTask);

        String processInstanceId = delegateTask.getProcessInstanceId();
        LOGGER.debug("enter the signuser listener notify method, taskId:"+ delegateTask.getId() + " assignee:"+ delegateTask.getAssignee());

        Integer instanceOfNumbers=(Integer)delegateTask.getVariable("nrOfInstances");
        Integer loopCounter=(Integer)delegateTask.getVariable("loopCounter");

        if (loopCounter == null) {
            loopCounter = 0;
        }

        LOGGER.debug("instance of numbers:"+ instanceOfNumbers + " loopCounters:"+ loopCounter);

        if (loopCounter == 0) {
            // 第一次进入执行
            addSignData(delegateTask, nodeId, processInstanceId, instanceOfNumbers);
        }
        // 添加流程状态
        bpmProStatusService.addOrUpd(procDefId, processInstanceId, nodeId);

        // 跟新会签数据任务id
        updTaskSignData(processInstanceId, nodeId, taskExecutor, delegateTask.getId());
    }

    /**
     * 更新会签数据的任务Id。
     * @param processInstanceId 流程实例id
     * @param nodeId 节点id
     * @param taskExecutor 执行人
     * @param taskId 任务id
     */
    private void updTaskSignData(String processInstanceId, String nodeId, TaskExecutor taskExecutor, String taskId) {
        String executorId= taskExecutor.getExecuteId();
        TaskSignData taskSignData =taskSignDataService.getUserTaskSign(processInstanceId, nodeId,  executorId);
        if (taskSignData == null) {
            return;
        }
        taskSignData.setTaskId(taskId);
        taskSignDataService.update(taskSignData);
    }

    /**
     * 添加会签数据
     * @param delegateTask 代理任务
     * @param nodeId 节点id
     * @param processInstanceId 流程实例id
     * @param instanceOfNumbers 总实例数
     */
    private void addSignData(DelegateTask delegateTask, String nodeId, String processInstanceId, Integer instanceOfNumbers) {
        Map<String, List<TaskExecutor>> nodeUserMap = taskUserAssignService.getNodeUserMap();
        if (BeanUtils.isEmpty(nodeUserMap)) {
            return;
        }

        List<TaskExecutor> signUserList = nodeUserMap.get(nodeId);
        if (BeanUtils.isEmpty(signUserList)) {
            return;
        }

        Integer batch = taskSignDataService.getMaxBatch(processInstanceId, nodeId);
        if (batch == null) {
            batch = 0;
        }
        batch += 1;

        for (int i = 0; i < instanceOfNumbers; i++) {
            int sn = i+1;
            // 生成投票数据
            TaskSignData signData=new TaskSignData();
            signData.setProcInstId(processInstanceId);

            signData.setNodeName(delegateTask.getName());
            signData.setNodeId(nodeId);
            signData.setSignNums(sn);
            signData.setIsCompleted(TaskSignData.NOT_COMPLETED);

            TaskExecutor signUser=signUserList.get(i);
            if(signUser!=null){
                signData.setVoteUserId(signUser.getExecuteId());
                signData.setVoteUserName(signUser.getExecutor());
            }
            signData.setDataId(UUIDUtils.getUUIDFor32());
            signData.setBatch(batch);

            taskSignDataService.add(signData);
        }



    }

    /**
     * 分配任务执行人
     * @param delegateTask 代理任务
     * @param taskExecutor 任务执行人
     */
    private void assignTaskExecutor(DelegateTask delegateTask, TaskExecutor taskExecutor) {
        //获取表单密级
        int dataPrivacyLevel = getDataPrivacyLevel(delegateTask);
        // 设置执行人
        if (TaskExecutor.USER_TYPE_USER.equalsIgnoreCase(taskExecutor.getType())) {
            String sysUserId = taskExecutor.getExecuteId();
            Map<String,Object> result = setAssignUser(delegateTask, sysUserId,dataPrivacyLevel);
            if((int)result.get(RESULT_NAME)==0){
                //由于密级不足导致没有执行人
                String msg=result.get(RESULT_MSG_NAME).toString();
                MessageUtil.addMsg(msg);
                throw new RuntimeException(msg);
            }
        }else{
            delegateTask.setAssignee(BpmConst.EMPTY_USER);
            delegateTask.setOwner(BpmConst.EMPTY_USER);
            // 二次抽取
            if (TaskExecutor.EXACT_EXACT_SECOND == taskExecutor.getExactType()||TaskExecutor.EXACT_NOEXACT == taskExecutor.getExactType()) {
                List<SysUser> userList = BpmNodeUserUtil.getUserListByExecutor(taskExecutor);
                if (BeanUtils.isEmpty(userList)) {
                    String msg="[" +taskExecutor.getExecutor() +"],没有设置人员,请先设置人员。";
                    MessageUtil.addMsg(msg);
                    throw new RuntimeException(msg);
                }

                //由于密级限制，应该把所有的用户都抽取出来进行筛选
                Set<String> userSet = new LinkedHashSet<>(16);
                for (SysUser sysUser : userList) {
                    if(SecretUtil.getUserDataSecretMap().get(sysUser.getPrivacyLevel())>=dataPrivacyLevel){
                        delegateTask.addCandidateUser(sysUser.getUserId());
                        userSet.add(sysUser.getUserId());
                    }
                }
                if(userSet.size()<=0){
                    String msg="设置的人员密级不够!";
                    MessageUtil.addMsg(msg);
                    throw new RuntimeException(msg);
                }
            }
            // 不抽取
            /*else if (TaskExecutor.EXACT_NOEXACT == taskExecutor.getExactType()) {
                delegateTask.addGroupIdentityLink(taskExecutor.getExecuteId(), taskExecutor.getType());
            }*/
            //用户组
            else if (TaskExecutor.EXACT_USER_GROUP == taskExecutor.getExactType()) {
                String[] aryExecutor=taskExecutor.getExecuteId().split(",");
                if(aryExecutor.length==1){
                    String sysUserId = taskExecutor.getExecuteId();
                    Map<String,Object> result =  setAssignUser(delegateTask, sysUserId,dataPrivacyLevel);
                    if((int)result.get(RESULT_NAME)==0){
                        //由于密级不足导致没有执行人
                        String msg=result.get(RESULT_MSG_NAME).toString();
                        MessageUtil.addMsg(msg);
                        throw new RuntimeException(msg);
                    }
                }
                else{
                    Set<String> userSet = new LinkedHashSet<>(16);
                    SysUser tempUser;
                    for(String executorId:aryExecutor){
                        tempUser = sysUserService.getById(executorId);
                        if(tempUser.getPrivacyLevel()>=dataPrivacyLevel){
                            delegateTask.addCandidateUser(executorId);
                            userSet.add(executorId);
                        }
                    }
                    if(userSet.size()<=0){
                        String msg="设置的人员密级不够!";
                        MessageUtil.addMsg(msg);
                        throw new RuntimeException(msg);
                    }
                }
            }
        }
    }

    /**
     * 设置任务执行人
     * @param delegateTask 代理任务
     * @param sysUserId 执行人id
     */
    private Map<String,Object> setAssignUser(DelegateTask delegateTask,String sysUserId,int dataPrivacyLevel){
        Map<String,Object> result = new HashMap<>(2);
        SysUser exeUser = sysUserService.getById(sysUserId);
        if(exeUser.getPrivacyLevel()<dataPrivacyLevel){
            result.put(RESULT_NAME,0);
            result.put(RESULT_MSG_NAME,"下一节点审批人的密级不够！");
            return result;
        }
        SysUser agentUser = null;
        if (isAllowAgent()) {
            agentUser = agentSettingService.getAgent(delegateTask, sysUserId);
        }

        if (BeanUtils.isNotEmpty(agentUser)) {
            if(agentUser.getPrivacyLevel()<dataPrivacyLevel){
                result.put(RESULT_NAME,0);
                result.put(RESULT_MSG_NAME,"代理人员的密级不够！");
                return result;
            }
            delegateTask.setAssignee(agentUser.getUserId());
            delegateTask.setDescription(TaskOpinion.STATUS_AGENT.toString());
        }else {
            delegateTask.setAssignee(sysUserId);
        }
        delegateTask.setOwner(sysUserId);
        TaskOpinion taskOpinion = taskOpinionService.getByTaskId(delegateTask.getId());
        taskOpinion.setExeUserId(exeUser.getUserId());
        taskOpinion.setExeFullname(exeUser.getFullName());
        taskOpinionService.update(taskOpinion);
        //成功进行人员分配操作
        result.put(RESULT_NAME,1);
        return result;
    }

    @Override
    protected int getBeforeScriptType() {
        return BpmConst.START_BEFORE_SCRIPT;
    }
}
